<?php

namespace App\Http\Controllers\AgentAdmin;

use App\Enums\ProductType;
use App\Exports\ChannelOrderExport;
use App\Exports\ChannelUserExport;
use App\Http\Controllers\Controller;
use App\Jobs\DownloadsJob;
use App\Models\AgentUser;
use App\Models\Channel;
use App\Models\Download;
use App\Models\FrontendUser;
use App\Models\Order;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Vinlon\Laravel\LayAdmin\Exceptions\AdminException;
use Vinlon\Laravel\LayAdmin\PaginateResponse;

class ChannelController extends Controller
{
    public function index()
    {
        /** @var AgentUser $user */
        $user = auth()->user();

        $query = Channel::query()
            ->where('agent_id', $user->agent_id)
            ->with(['parent'])
            ->when(request()->keyword, function ($q) {
                return $q->where(function ($q2) {
                    $likeVal = '%' . request()->keyword . '%';

                    return $q2->where('contact', 'like', $likeVal)->orWhere('name', 'like', $likeVal)->orWhere('mobile', 'like', $likeVal);
                });
            })
            ->orderByDesc('id');

        return paginate_result($query);
    }

    /**
     * 查询渠道指标.
     *
     * @param $id
     *
     * @return array[]
     */
    public function target($id): array
    {
        $startDate = request()->start_date;
        $endDate = request()->end_date;

        if (!empty($startDate)) {
            $startDate = Carbon::parse($startDate)->startOfDay()->toDateTimeString();
            $endDate = Carbon::parse($endDate)->endOfDay()->toDateTimeString();

            $orders = DB::select("SELECT c.channel_id , b.type , count(*) AS order_count , sum(order_amount) AS order_amount FROM op_orders AS a INNER JOIN op_products AS b ON a.product_id = b.id INNER JOIN op_frontend_users AS c ON a.user_id = c.id WHERE a.order_status = 'paid' AND c.channel_id = {$id} AND a.created_at >= '{$startDate}' AND a.created_at <= '{$endDate}' group by b.type");
            $users = DB::select("SELECT a.channel_id,count(a.id)as user_count, COUNT(b.id) as real_user_count FROM op_frontend_users AS a LEFT JOIN op_user_auths AS b ON a.id = b.user_id WHERE a.channel_id = {$id} AND a.created_at >= '{$startDate}' AND a.created_at <= '{$endDate}'");
        } else {
            $orders = DB::select("SELECT c.channel_id , b.type , count(*) AS order_count , sum(order_amount) AS order_amount FROM op_orders AS a INNER JOIN op_products AS b ON a.product_id = b.id INNER JOIN op_frontend_users AS c ON a.user_id = c.id WHERE a.order_status = 'paid' AND c.channel_id = {$id}  group by b.type");
            $users = DB::select("SELECT a.channel_id,count(a.id)as user_count, COUNT(b.id) as real_user_count FROM op_frontend_users AS a LEFT JOIN op_user_auths AS b ON a.id = b.user_id WHERE a.channel_id = {$id}");
        }

        $channelOrder = $userData = [];
        foreach ($orders as $order) {
            $channelOrder[$order->type]['order_amount'] = $order->order_amount;
            $channelOrder[$order->type]['order_count'] = $order->order_count;
        }

        foreach ($users as $user) {
            $userData['user_count'] = $user->user_count;
            $userData['real_user_count'] = $user->real_user_count;
        }

        $arr['pay_order'] = array_sum(array_map(function ($value) {
            return $value['order_count'];
        }, $channelOrder));

        $arr['resale_order_amount'] = toYuan($channelOrder[ProductType::RESALE]['order_amount'] ?? 0);
        $arr['blind_order_amount'] = toYuan($channelOrder[ProductType::BLIND_BOX]['order_amount'] ?? 0);
        $arr['order_amount'] = toYuan($channelOrder[ProductType::ISSUE]['order_amount'] ?? 0);
        $arr['pay_order_money'] = round(
            $arr['resale_order_amount'] + $arr['blind_order_amount'] + $arr['order_amount'],
            2
        );
        $arr['user_count'] = $userData['user_count'] ?? 0;
        $arr['real_user_count'] = $userData['real_user_count'] ?? 0;

        return [$arr];
    }

    public function listChannels(): PaginateResponse
    {
        /** @var AgentUser $user */
        $user = auth()->user();
        $query = Channel::query()
            ->where('agent_id', $user->agent_id)
            ->when(request()->keyword, function ($q) {
                return $q->where(function ($q2) {
                    $likeVal = '%' . request()->keyword . '%';

                    return $q2->where('contact', 'like', $likeVal)->orWhere('mobile', 'like', $likeVal);
                });
            })
            ->orderByDesc('id');

        $ids = $query->pluck('id')->toArray();
        $ids = implode(',', $ids);
        $orders = DB::select("SELECT c.channel_id , b.type , count(*) AS order_count , sum(order_amount) AS order_amount FROM op_orders AS a INNER JOIN op_products AS b ON a.product_id = b.id INNER JOIN op_frontend_users AS c ON a.user_id = c.id WHERE a.order_status = 'paid' AND c.channel_id IN({$ids}) GROUP BY c.channel_id , b.type");

        $channelOrder = $userData = [];
        foreach ($orders as $order) {
            if (!isset($channelOrder[$order->channel_id])) {
                $channelOrder[$order->channel_id] = [];
            }
            $channelOrder[$order->channel_id][$order->type]['order_amount'] = $order->order_amount;
            $channelOrder[$order->channel_id][$order->type]['order_count'] = $order->order_count;
        }

        $users = DB::select("SELECT a.channel_id,count(a.id)as user_count, COUNT(b.id) as real_user_count FROM op_frontend_users AS a LEFT JOIN op_user_auths AS b ON a.id = b.user_id WHERE a.channel_id IN({$ids}) GROUP BY a.channel_id");

        foreach ($users as $user) {
            if (!isset($userData[$user->channel_id])) {
                $userData[$user->channel_id] = [];
            }
            $userData[$user->channel_id]['user_count'] = $user->user_count;
            $userData[$user->channel_id]['real_user_count'] = $user->real_user_count;
        }

        return paginate_result($query, function (Channel $channel) use ($channelOrder, $userData) {
            $arr = $channel->toArray();
            $channelOrder = $channelOrder[$channel->id] ?? [];

            $arr['pay_order'] = array_sum(array_map(function ($value) {
                return $value['order_count'];
            }, $channelOrder));
            $arr['resale_order_amount'] = toYuan($channelOrder[ProductType::RESALE]['order_amount'] ?? 0);
            $arr['blind_order_amount'] = toYuan($channelOrder[ProductType::BLIND_BOX]['order_amount'] ?? 0);
            $arr['order_amount'] = toYuan($channelOrder[ProductType::ISSUE]['order_amount'] ?? 0);
            $arr['pay_order_money'] = round(
                $arr['resale_order_amount'] + $arr['blind_order_amount'] + $arr['order_amount'],
                2
            );

            $arr['user_count'] = $userData[$channel->id]['user_count'] ?? 0;
            $arr['real_user_count'] = $userData[$channel->id]['real_user_count'] ?? 0;

            return $arr;
        });
    }

    public function listSimpleChannels(): array
    {
        /** @var AgentUser $user */
        $user = auth()->user();
        $query = Channel::query()
            ->select(['id', 'name'])
            ->where('agent_id', $user->agent_id)
            ->orderByDesc('id');

        return $query->get()->toArray();
    }

    public function store()
    {
        /** @var AgentUser $agentUser */
        $agentUser = auth()->user();
        /** @var Channel $channel */
        $channel = get_entity(Channel::class);
        $existQuery = Channel::query()->where('agent_id', $agentUser->agent_id)->where('mobile', request()->mobile);
        if ($channel->id) {
            $existQuery->where('id', '!=', $channel->id);
        } else {
            $channel->uuid = Str::random(16);
            $channel->agent_id = $agentUser->agent_id;
        }
        // 查询手机号是否已被注册
        if ($existQuery->exists()) {
            throw new AdminException('渠道手机号已被使用.');
        }
        $parentCode = request()->parent_code;
        /** @var Channel $parent */
        $parent = Channel::query()->where('uuid', $parentCode)->first();
        if (!$parent) {
            throw new AdminException('无效的上级渠道码');
        }
        if (0 != $parent->parent_id) {
            throw new AdminException('上级渠道必须是一级渠道');
        }
        $channel->parent_id = $parent->id;
        $channel->name = request()->name;
        $channel->contact = request()->contact;
        $channel->mobile = request()->mobile;
        $channel->cover_image_url = request()->cover_image_url;
        $channel->daily_register_limit = request()->daily_register_limit;

        $channel->save();
    }

    public function userexport()
    {
        /** @var AgentUser $user */
        $user = auth()->user();

        $file = '渠道用户' . date('YmdHis') . uniqid() . '.xls';

        $download = Download::create([
            'agent_id' => $user->agent_id,
            'user_id' => $user->id,
            'name' => $file,
            'url' => 'storage/' . $file,
            'status' => 0,
            'model' => ChannelUserExport::class,
            'request' => json_encode(request()->all()),
        ]);

        dispatch(new DownloadsJob($download));
    }

    public function orderexport()
    {
        /** @var AgentUser $user */
        $user = auth()->user();

        $file = '渠道订单' . date('YmdHis') . uniqid() . '.xls';

        $download = Download::create([
            'agent_id' => $user->agent_id,
            'user_id' => $user->id,
            'name' => $file,
            'url' => 'storage/' . $file,
            'status' => 0,
            'model' => ChannelOrderExport::class,
            'request' => json_encode(request()->all()),
        ]);

        dispatch(new DownloadsJob($download));
    }

    private function getAgentOrdersQuery(ProductType $type = null)
    {
        /** @var AgentUser $user */
        $user = auth()->user();
        $userIds = FrontendUser::query()->where('channel_id', request()->channel_id)->pluck('id');

        return Order::query()
            ->with(['user', 'payment'])
            ->whereIn('user_id', $userIds)
            ->when(request()->start_date, function ($q) {
                return $q->whereDate('created_at', '>=', request()->start_date);
            })
            ->when(request()->end_date, function ($q) {
                return $q->whereDate('created_at', '>=', request()->end_date);
            })->when($type, function ($query) use ($type) {
                return $query->whereHas('product', function ($q) use ($type) {
                    return $q->where('type', $type->value);
                });
            })
            ->where('agent_id', $user->agent_id)
            ->orderByDesc('id');
    }
}
